package stone926.mods.more_enchantments.mixins;

import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import stone926.mods.more_enchantments.MoreEnchantmentsMod;
import stone926.mods.more_enchantments.damage.StoneDamageSource;
import stone926.mods.more_enchantments.enchantments.MultiplyCurseEnchantment;
import stone926.mods.more_enchantments.util.BlockUtil;
import stone926.mods.more_enchantments.util.RandomUtil;

import static stone926.mods.more_enchantments.enchantments.MultiplyCurseEnchantment.*;

@Mixin(Block.class)
public abstract class BlockMixin extends AbstractBlock implements ItemConvertible {

  public BlockMixin(Settings settings) {
    super(settings);
  }

  @Shadow
  public static void dropStacks(BlockState state, World world, BlockPos pos, @Nullable BlockEntity blockEntity, Entity entity, ItemStack stack) {}

  @Inject(method = "afterBreak", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;dropStacks(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/entity/BlockEntity;Lnet/minecraft/entity/Entity;Lnet/minecraft/item/ItemStack;)V"), cancellable = true)
  private void afterBreak1(World world, PlayerEntity player, BlockPos pos, BlockState state, BlockEntity blockEntity, ItemStack stack, CallbackInfo ci) {
    if (BlockUtil.canUseCompressedStonePickaxe(player, state)) {
      player.setCurrentHand(Hand.MAIN_HAND);
      Block.dropStack(world, pos, new ItemStack(state.getBlock()));
      ci.cancel();
    }
  }

  @Inject(method = "afterBreak", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;dropStacks(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/entity/BlockEntity;Lnet/minecraft/entity/Entity;Lnet/minecraft/item/ItemStack;)V"), cancellable = true)
  public void afterBreak2(World world, PlayerEntity player, BlockPos pos, BlockState state, BlockEntity blockEntity, ItemStack stack, CallbackInfo ci) {
    int destroyCurseLvl = EnchantmentHelper.getLevel(MoreEnchantmentsMod.DESTROY_CURSE, stack);
    int multiplyCurseLvl = EnchantmentHelper.getLevel(MoreEnchantmentsMod.MULTIPLY_CURSE, stack);
    if (destroyCurseLvl > 0) {
      ci.cancel();
    } else if (multiplyCurseLvl > 0) {
      for (int i = 0; i < multiplyCurseLvl; i++) {
        RandomUtil.runIfPossible(
          MultiplyCurseEnchantment.getDropStackProbability(multiplyCurseLvl),
          player.getRandom(),
          () -> dropStacks(state, world, pos, blockEntity, player, stack)
        );
      }
      player.damage(StoneDamageSource.MULTIPLY_CURSE, getPlayerDamageAmount(multiplyCurseLvl, player));
      damageOrVanishArmor(player, multiplyCurseLvl, getArmorDamageAmount(multiplyCurseLvl, player));
    }
  }


  private void damageOrVanishArmor(PlayerEntity player, int lvl, int amount) {
    ItemStack stack = player.getInventory().getArmorStack(player.getRandom().nextInt(4));
    if (stack.getItem() instanceof ArmorItem armor) {
      stack.damage(
        RandomUtil.isPossible(getArmorRemovedProbability(lvl), player.getRandom()) ? stack.getMaxDamage() : amount, player,
        p -> p.sendEquipmentBreakStatus(armor.getSlotType())
      );
    }
  }

}
